package com.example;

import java.util.*;

/**
 * 公交车
 */
public class Bus extends Thread {
    private static final long ZOOM = 10L;
    /**
     * 初始时间点
     */
    private static final long INIT_TIME_POINT = System.currentTimeMillis() / ZOOM;
//    private Site upRouteStartSite;
//    private Site upRouteEndtSite;
//    private Site downRouteStartSite;
//    private Site downRouteEndSite;

    @Override
    public void run() {
        //发车了
        try {
            //发车了
            depart();
            while (true) {
                //到站了
                arrivalSite();
                //上下客
                upDownGuest();
                //再次出发
                againDepart();
                synchronized (Bus.class) {
                    System.out.println("=====================================");
                    System.out.println(this);
                }
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    //再次发车
    private void againDepart() {
        Trace trace = new Trace();
        trace.setTraceAction(Trace.TraceAction.DEPART);
        trace.setSiteName(currentSite.getName());
        trace.setTimePoint(calculateCurrentTimePoint());
        trace.setTraceAction(Trace.TraceAction.DEPART);
        trace.setCurrentGuest(currentGuests.size());
        addTrace(trace);
    }

    private void upDownGuest() throws InterruptedException {
        //下客
        int downGuestNum = downGuest();
        Thread.sleep(downGuestNum * 10 * ZOOM);
        //上客
        int upGuestNum = upGuest(currentSite.getUpGuests(getAllowUpGuest()));
        Thread.sleep(upGuestNum * 10 * ZOOM);
    }

    /**
     * 到站了
     */
    private void arrivalSite() throws InterruptedException {
        //到下一站还有需要多少时间
        Thread.sleep(currentSite.getNextArrivalTime() * ZOOM);
        currentSite = currentSite.getNextSite();
        Trace trace = new Trace();
        trace.setTimePoint(calculateCurrentTimePoint());
        trace.setSiteName(currentSite.getName());
        trace.setTraceAction(Trace.TraceAction.ARRIVAL);
        trace.setCurrentGuest(currentGuests.size());
        addTrace(trace);
    }

    /**
     * 追加行驶日志
     *
     * @param trace
     */
    private void addTrace(Trace trace) {
        this.traces.add(trace);
    }

    private int nextArrivalTime = 0;

    /**
     * 计算当前时间点
     */
    public long calculateCurrentTimePoint() {
        long timePoint = (System.currentTimeMillis() / ZOOM) - INIT_TIME_POINT;
        return timePoint;
    }

    /**
     * 最大乘客数，29
     */
    private final static Integer MAX_GUEST = 29;

    /**
     * 公交车名称
     */
    private String busName;

    /**
     * 发车时间
     */
    private int departTime;

    /**
     * 总载客数
     */
//    int totalSeatingCapacity;

    /**
     * 总运行时长
     */
    private int totalWorkingTime;

    /**
     * 总驾驶时间
     */
    private int totalDriveTime;

    /**
     * 当前所在站点
     */
    private Site currentSite;

    /**
     * 当前乘客列表
     */
    private Set<Guest> currentGuests = new HashSet<>();

    /**
     * 发车
     */
    public void depart() throws InterruptedException {
        Thread.sleep(departTime * ZOOM);
        Trace trace = new Trace();
        trace.setTraceAction(Trace.TraceAction.DEPART);
        trace.setSiteName(currentSite.getName());
        addTrace(trace);
        int allowUpGuest = getAllowUpGuest();
        List<Guest> upGuests = currentSite.getUpGuests(allowUpGuest);
        upGuest(upGuests);
        trace.setCurrentGuest(currentGuests.size());
    }

    /**
     * 每次变化的追踪列表
     */
    private List<Trace> traces = new ArrayList<>();

    public Bus(String busName, Site currentSite, int departTime) {
        this.busName = busName;
        this.currentSite = currentSite;
        this.departTime = departTime;
//        this.upRouteStartSite = upRouteStartSite;
//        this.upRouteEndtSite = upRouteEndtSite;
//        this.downRouteStartSite = downRouteStartSite;
//        this.downRouteEndSite = downRouteEndSite;
    }

    public String getBusName() {
        return busName;
    }

    public void setBusName(String name) {
        this.busName = name;
    }

    public int getTotalWorkingTime() {
        return totalWorkingTime;
    }

    public void setTotalWorkingTime(int totalWorkingTime) {
        this.totalWorkingTime = totalWorkingTime;
    }

    public int getTotalDriveTime() {
        return totalDriveTime;
    }

    public void setTotalDriveTime(int totalDriveTime) {
        this.totalDriveTime = totalDriveTime;
    }

    public Site getCurrentSite() {
        return currentSite;
    }

    public void setCurrentSite(Site currentSite) {
        this.currentSite = currentSite;
    }

    public Set<Guest> getCurrentGuests() {
        return currentGuests;
    }

    public int getAllowUpGuest() {
        return MAX_GUEST - this.currentGuests.size();
    }

    public int upGuest(Collection<Guest> guests) {
        Trace trace = getLastTrace();
        this.currentGuests.addAll(guests);
        trace.setUpGuest(guests.size());
        trace.setCurrentGuest(this.currentGuests.size());
        return guests.size();
    }

    public int downGuest() {
        Trace trace = new Trace();
        trace.setTraceAction(Trace.TraceAction.UP_DOWN_GUEST);
        trace.setTimePoint(calculateCurrentTimePoint());
        trace.setSiteName(currentSite.getName());
        addTrace(trace);

        Set<Guest> remove = new HashSet<>();
//        if (currentSite.equals(upRouteEndtSite) || currentSite.equals(downRouteEndSite)) {
//            remove.addAll(currentGuests);
//        } else {

            for (Guest guest : this.currentGuests) {
                if (this.currentSite.equals(guest.getTargetSite())) {
                    remove.add(guest);
                }
            }
//        }
        this.currentGuests.removeAll(remove);
        trace.setDownGuest(remove.size());
        return remove.size();
    }

    public List<Trace> getTraces() {
        return traces;
    }

    public Trace getLastTrace() {
        if (traces.size() > 0) {
            return traces.get(traces.size() - 1);
        }
        throw new IllegalStateException("没有公交行驶日志");
    }

    @Override
    public String toString() {
        return "Bus{" +
                "公交车号: '" + busName + '\'' +
                ", 当前站点: " + currentSite.getName() +
                ", 当前乘客数: " + currentGuests.size() +
                ", 记录列表: \n" +
                traces.get(traces.size() - 3) + "\n" +
                traces.get(traces.size() - 2) + "\n" +
                traces.get(traces.size() - 1) + "\n" +
                '}';
    }
}
